package cgl.narada.wsinfra.wsa.impl;

import cgl.narada.wsinfra.schemas.addressing.ActionDocument;
import cgl.narada.wsinfra.schemas.addressing.EndpointReferenceType;
import cgl.narada.wsinfra.schemas.addressing.FaultToDocument;
import cgl.narada.wsinfra.schemas.addressing.FromDocument;
import cgl.narada.wsinfra.schemas.addressing.MessageIDDocument;
import cgl.narada.wsinfra.schemas.addressing.RelatesToDocument;
import cgl.narada.wsinfra.schemas.addressing.ReplyAfterDocument;
import cgl.narada.wsinfra.schemas.addressing.ReplyToDocument;
import cgl.narada.wsinfra.schemas.addressing.ToDocument;
import cgl.narada.wsinfra.schemas.soap.BodyType;
import cgl.narada.wsinfra.schemas.soap.EnvelopeDocument;
import cgl.narada.wsinfra.schemas.soap.EnvelopeType;
import cgl.narada.wsinfra.schemas.soap.HeaderType;
import cgl.narada.wsinfra.util.SoapMessageAlteration;
import cgl.narada.wsinfra.util.UUIDRetrieval;
import cgl.narada.wsinfra.wsa.WsaEnvelopeCreator;
import cgl.narada.wsinfra.wsa.WsaEprRules;
import cgl.narada.wsinfra.wsa.WsaProcessingFactory;

/** This is a utility which creates SOAP enevelopes initialized to the
    specified WSA headers.

    @author Shrideep Pallickara
    $Date: 2005/03/25 15:43:39 $
    $Revision: 1.4 $
*/


public class WsaEnvelopeCreatorImpl implements  WsaEnvelopeCreator {
  private static final WsaEnvelopeCreator instance =
  new WsaEnvelopeCreatorImpl();
  private WsaEprRules wsaEprRules;
  private SoapMessageAlteration soapMessageAlteration;
  private UUIDRetrieval retriever;

  private String moduleName = "WsaEnvelopeCreator: ";


  private WsaEnvelopeCreatorImpl() {
    wsaEprRules = WsaProcessingFactory.getWsaEprRules();
    retriever = UUIDRetrieval.getInstance();
    soapMessageAlteration = SoapMessageAlteration.getInstance();
  }


  public static WsaEnvelopeCreator getInstance() {
    return instance;
  }
  /** Prepare SOAP envelope based on the specified WS-Addressing headers */
  public EnvelopeDocument
  createSoapEnvelope(EndpointReferenceType to, FromDocument from,
		     ActionDocument action) {
    if (to == null) {
      System.out.println(moduleName + "The specified (To) element is NULL");
      return null;
    }

    EnvelopeDocument envelopeDocument = wsaEprRules.prepareSOAPEnvelope(to);

    if (envelopeDocument == null) {
      System.out.println(moduleName + "The initialized envelope is NULL!");
      return null;
    }

    MessageIDDocument messageID = getMessageIDDocument();

    soapMessageAlteration.addToSoapHeader(envelopeDocument, from);
    soapMessageAlteration.addToSoapHeader(envelopeDocument, messageID);
    soapMessageAlteration.addToSoapHeader(envelopeDocument, action);

    return envelopeDocument;
  }


  /** Prepare SOAP envelope based on the specified WS-Addressing headers */
  public EnvelopeDocument
  createSoapEnvelope(EndpointReferenceType to, FromDocument from,
		     ActionDocument action, RelatesToDocument relatesTo) {
    if (to == null) {
      System.out.println(moduleName + "The specified (To) element is NULL");
      return null;
    }

    EnvelopeDocument envelopeDocument = wsaEprRules.prepareSOAPEnvelope(to);

    if (envelopeDocument == null) {
      System.out.println(moduleName + "The initialized envelope is NULL!");
      return null;
    }

    MessageIDDocument messageID = getMessageIDDocument();

    soapMessageAlteration.addToSoapHeader(envelopeDocument, from);
    soapMessageAlteration.addToSoapHeader(envelopeDocument, messageID);
    soapMessageAlteration.addToSoapHeader(envelopeDocument, relatesTo);
    soapMessageAlteration.addToSoapHeader(envelopeDocument, action);

    return envelopeDocument;
  }


  /** Prepare SOAP envelope based on the specified WS-Addressing headers */
  public EnvelopeDocument
  createSoapEnvelope(EndpointReferenceType to, FromDocument from,
		     ActionDocument action,
		     ReplyToDocument replyTo, ReplyAfterDocument replyAfter,
		     FaultToDocument faultTo) {
    if (to == null) {
      System.out.println(moduleName + "The specified (To) element is NULL");
      return null;
    }

    EnvelopeDocument envelopeDocument = wsaEprRules.prepareSOAPEnvelope(to);

    if (envelopeDocument == null) {
      System.out.println(moduleName + "The initialized envelope is NULL!");
      return null;
    }

    MessageIDDocument messageID = getMessageIDDocument();

    soapMessageAlteration.addToSoapHeader(envelopeDocument, from);
    soapMessageAlteration.addToSoapHeader(envelopeDocument, messageID);
    soapMessageAlteration.addToSoapHeader(envelopeDocument, replyTo);
    soapMessageAlteration.addToSoapHeader(envelopeDocument, replyAfter);
    soapMessageAlteration.addToSoapHeader(envelopeDocument, faultTo);
    soapMessageAlteration.addToSoapHeader(envelopeDocument, action);

    return envelopeDocument;
  }



  /** Prepare SOAP envelope based on the specified WS-Addressing headers */
  public EnvelopeDocument
  createSoapEnvelope(ToDocument to, FromDocument from,
		     ActionDocument action,
		     ReplyToDocument replyTo, ReplyAfterDocument replyAfter,
		     FaultToDocument faultTo) {
    if (to == null) {
      System.out.println(moduleName + "The specified (To) element is NULL");
      return null;
    }

    EnvelopeDocument envelopeDocument = prepareSOAPEnvelope();
    MessageIDDocument messageID = getMessageIDDocument();
    
    soapMessageAlteration.addToSoapHeader(envelopeDocument, from);
    soapMessageAlteration.addToSoapHeader(envelopeDocument, messageID);
    soapMessageAlteration.addToSoapHeader(envelopeDocument, replyTo);
    soapMessageAlteration.addToSoapHeader(envelopeDocument, replyAfter);
    soapMessageAlteration.addToSoapHeader(envelopeDocument, faultTo);
    soapMessageAlteration.addToSoapHeader(envelopeDocument, action);
    soapMessageAlteration.addToSoapHeader(envelopeDocument, to);

    return envelopeDocument;
  }


  /** Prepare SOAP Envelope based on the specified WS-Addressing header. This
      method is specifically used by WS-Eventing sources where there 
      application does not know where a message would be sent. This method
      creates the MessageID element automatically. */
  public EnvelopeDocument createSoapEnvelope(FromDocument from) {
    if (from == null) {
      System.out.println(moduleName + "The specified (FROM) element is NULL");
      return null;
    }

    EnvelopeDocument envelopeDocument = prepareSOAPEnvelope();
    MessageIDDocument messageID = getMessageIDDocument();
    
    soapMessageAlteration.addToSoapHeader(envelopeDocument, from);
    soapMessageAlteration.addToSoapHeader(envelopeDocument, messageID);
    
    return envelopeDocument;
  }


  private EnvelopeDocument prepareSOAPEnvelope() {
    EnvelopeDocument envelopeDocument = EnvelopeDocument.Factory.newInstance();
    EnvelopeType envelope = envelopeDocument.addNewEnvelope();
    
    /** First prepare the header of the SOAP envelope to contain the
	action Attribute value */
    HeaderType header = envelope.addNewHeader();
    
    /** Add a body to this SOAP Envelope */
    BodyType body = envelope.addNewBody();
    return envelopeDocument;
  }


  /** Retrieve a newly created messageID document */
  private MessageIDDocument getMessageIDDocument() {
    String messageUuid = retriever.getRandomBasedUUIDAsString();
    MessageIDDocument messageID = MessageIDDocument.Factory.newInstance();
    messageID.addNewMessageID().setStringValue(messageUuid);
    return messageID;
  }

}